package org.hsqldb;

import java.io.IOException;
import org.hsqldb.index.NodeLinkList;
import org.hsqldb.persist.PersistentStore;
import org.hsqldb.rowio.RowInputInterface;
import org.hsqldb.rowio.RowOutputInterface;

public class RowLinkListData extends RowLinkList{
	PersistentStore store;
    int             accessCount;
    boolean         hasDataChanged;
    int             storageSize;
    
    public RowLinkListData(TableBase table, Object[] data, int position,
            PersistentStore store) {

	  super(table,data,position,store);
	}
    /**
     *  Constructor for new rows.
     */
    public RowLinkListData(PersistentStore store, TableBase t, Object[] o) {

        super(t, o);

        setNewNodes(store);

        hasDataChanged = true;
        this.store     = store;
    }
	
    /**
     *  Constructor when read from the disk into the Cache. The link with
     *  the Nodes is made separetly.
     */
    public RowLinkListData(PersistentStore store, TableBase t,
                          RowInputInterface in) throws IOException {

        super(t, (Object[]) null);

        setNewNodes(store);

        position       = in.getPos();
        storageSize    = in.getSize();
        rowData        = in.readData(table.getColumnTypes());
        hasDataChanged = false;
        this.store     = store;
    }


	public static Object[] getRowData(TableBase t,
                                      RowInputInterface in)
                                      throws IOException {
        return in.readData(t.getColumnTypes());
    }

    public void setData(Object[] data) {
        this.rowData = data;
    }

    public Object[] getData() {

        Object[] data = rowData;

        if (data == null) {
            store.writeLock();

            try {
                store.get(this, false);

                data = rowData;

                if (data == null) {
                    store.get(this, false);

                    data = rowData;
                }
            } finally {
                store.writeUnlock();
            }
        } else {
            accessCount++;
        }

        return data;
    }

    /**
     *  Used when data is read from the disk into the Cache the first time.
     *  New Nodes are created which are then indexed.
     */
    public void setNewNodes(PersistentStore store) {

        int index = store.getAccessorKeys().length;

        nPrimaryNode = new NodeLinkList(this);

        NodeLinkList n = nPrimaryNode;

        for (int i = 1; i < index; i++) {
            n.nodeNextIndex = new NodeLinkList(this);
            n       = n.nodeNextIndex;
        }
    }



    /**
     *  Used when data is re-read from the disk into the Cache. The Row is
     *  already indexed so it is linked with the Node in the primary index.
     *  the Nodes is made separetly.
     */
    void setPrimaryNode(NodeLinkList primary) {
        nPrimaryNode = primary;
    }

    public int getRealSize(RowOutputInterface out) {
        return out.getSize(this);
    }

    /**
     *  Writes the data to disk. Unlike CachedRow, hasChanged is never set
     *  to true when changes are made to the Nodes. (Nodes are in-memory).
     *  The only time this is used is when a new Row is added to the Caches.
     */
    public void write(RowOutputInterface out) {

        out.writeSize(storageSize);
        out.writeData(this, table.colTypes);
        out.writeEnd();

        hasDataChanged = false;
    }

    public synchronized void setChanged(boolean changed) {
        hasDataChanged = changed;
    }

    public boolean hasChanged() {
        return hasDataChanged;
    }

    public void updateAccessCount(int count) {
        accessCount = count;
    }

    public int getAccessCount() {
        return accessCount;
    }

    public int getStorageSize() {
        return storageSize;
    }

    public void setStorageSize(int size) {
        storageSize = size;
    }

    /**
     * Sets the file position for the row and registers the row with
     * the table.
     *
     * @param pos position in data file
     */
    public void setPos(int pos) {
        position = pos;
    }

    public boolean isMemory() {
        return true;
    }

    /**
     * With the current implementation of TEXT table updates and inserts,
     * the lifetime scope of this method extends until redefinition of table
     * data source or shutdown.
     *
     * @param obj the reference object with which to compare.
     * @return <code>true</code> if this object is the same as the obj argument;
     *   <code>false</code> otherwise.
     */
    public boolean equals(Object obj) {
        return obj == this;
    }

    /** used by Index, nodes are always in memory */
    public boolean isInMemory() {
        return true;
    }
}
